package com.abo.yaas.webservice.utils;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;

import com.abo.yaas.domain.Auction;
import com.abo.yaas.domain.AuctionState;
import com.abo.yaas.domain.Bid;
import com.abo.yaas.domain.User;
import com.abo.yaas.webservice.CriteriaQueryUtil;
import com.abo.yaas.webservice.exceptions.WebServiceException;
import com.abo.yaas.webservice.hibernate.EntityManagerUtils;

public class BidFacade {
    
    public static Bid placeBid(final Bid bid) {
        final EntityManager em = EntityManagerUtils.getEntityManager();
        final Auction auction = em.getReference(Auction.class, bid.getAuctionId());
        CriteriaQueryUtil.runInTransaction(new Runnable() {
            @Override
            public void run() {
                try {
                    em.lock(auction, LockModeType.OPTIMISTIC);
                    if (bid != null) {
                        em.persist(bid);
                    }
                    auction.setLeadingBid(bid);
                } catch (final Exception e) {
                    throw new WebServiceException("Unsuccessful bid! Maybe u were overbid!");
                }
            }
        });
        return bid;
    }

    public static Bid doPlaceBid(final Bid bid) {
        final EntityManager em = EntityManagerUtils.getEntityManager();
        final Auction auction = em.find(Auction.class, bid.getAuctionId());

        if (auction == null) {
            throw new WebServiceException("The auction you are try to bid on does not exist!");
        }

        BidFacade.verifyAuctionStatus(auction);
        BidFacade.verifyAmountRestriction(auction, bid);
        BidFacade.verifyCurrentWinner(auction, bid);
        BidFacade.placeBid(bid);

        return bid;
    }
    
    public static void verifyAmountRestriction(final Auction auction, final Bid bid) {
        final Bid leadingBid = auction.getLeadingBid();
        if (leadingBid == null) {
            return;
        }
        if (bid.getAmount().doubleValue() <= leadingBid.getAmount().doubleValue()) {
            throw new WebServiceException("Your bid is too small! Maybe you have been overbid!");
        }
    }

    public static void verifyAuctionStatus(final Auction auction) throws WebServiceException {
        if (!auction.getState().equals(AuctionState.AS_ACTIVE)) {
            throw new WebServiceException("The auction is not active anymore!");
        }
    }

    public static void verifyCurrentWinner(final Auction auction, final Bid bid) {
        final User bidder = bid.getUser();
        final User auctionOwner = auction.getOwner();
        
        if (bidder == null) {
            throw new WebServiceException("Bidder must not be null!");
        }
        
        if (auctionOwner.equals(bidder)) {
            throw new WebServiceException("You cannot bid on your own auction!");
        }
        
        final Bid leadingBid = auction.getLeadingBid();
        if (leadingBid == null) {
            return;
        }
        final User currentWinner = leadingBid.getUser();
        if (bidder.equals(currentWinner)) {
            throw new WebServiceException("You are already winning this auction!");
        }
    }
}
